#include "userlib.h"

static char* allocbuffer(struct Range* range)
{
	char *ret;
	unsigned long len = range->end - range->start;
	ret = (char *)malloc(len + (len+PAGE_SIZE-1)/PAGE_SIZE);
	if(ret == 0) die("malloc");
	return ret;
}

int gettaskmem(struct Range* range, char **to)
{
	int result = -CANNOT_WRITE_RESULT;
	FILE *f;
	
	f=fopen("/proc/linalter", "w");
	if(f==0)
		die("/proc/linalter");
	if(*to == 0)
		*to = allocbuffer(range);
	fprintf(f, "c%ld %lx %lx %lx %lx", (long)range->pid, range->start, range->end - range->start, (unsigned long)*to, (unsigned long)&result);
	//printf("gettaskmem: %ld %lx %lx\n", (long)range->pid, range->start, range->end - range->start);
	fclose(f);
	if(result != 0){
		fprintf(stderr, "Error: %s\n", errormsg(result) );
		return -1;
	}else
		return 0;
}

void settaskmem(long pid, unsigned long addr, unsigned long long value, int len)
{
	union I v;
	int result;
	FILE *f;
	
	switch(len){
		case 8:
			v.i64 = (uint64_t)value; break;
		case 4:
			v.i32 = (uint32_t)value; break;
		case 2:
			v.i16 = (uint16_t)value; break;
		case 1:
			v.i8 = (uint8_t)value; break;
		default:
			printf("Unsupported length: %d\n", len);
			return;
	}
	f = fopen("/proc/linalter", "w");
	if(f){
		stoptask();
		fprintf(f, "w%ld %lx %lx %x %lx", pid, addr, (unsigned long)&v, len, (unsigned long)&result);
		fclose(f);
		if(result)
			fprintf(stderr, "%s\n", errormsg(result));
		continuetask();
	}else
		die("/proc/linalter");
}

static void findtarget(char buf[], unsigned long len, char targ[], int minlen, ResultSet *r)
{
	unsigned long i;
	int maxx;
	int j;
	for(i=0;i<len;i++){
		maxx = (len-i<8)?(len-i):8;
		for(j=1;j<=maxx;j*=2)
			if( strncmp(buf+i, targ, j)==0 ){
				r->add(i);
				break;
			}
	}
}

void searchtaskmem(unsigned long long value)
{
	struct Range *range;
	char *buf = 0;
	list<struct Range>::iterator it;
	union I v;
	int minl;
	ResultSet *result = new ResultSet(value);

	v.i64 = value;
	minl = minlen(value);
	stoptask();
	getwritablevma();
	if(writablevma.size()>0)
		for(it = writablevma.begin(); it != writablevma.end(); it ++){
			range = &(*it);
			if(gettaskmem(range, &buf)==0){
				result->range = range;
				findtarget(buf, range->end-range->start, v.c, minlen(value), result);
			}
			free(buf); buf=0;
		}
	continuetask();
	
	if(result->addrs.size()){
		result->printinfo();
		results.push_back(result);
	}else{
		printf("No result.\n");
		delete result;
	}
}

